package strain.domain;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import strain.expression.BaseExpression;
import strain.expression.EnumExpression;

public class EnumDomain<T> extends BaseExpression<T, EnumDomain<T>> implements EnumExpression<T>, DiscreteDomain<T> {

    protected final Set<T> set;
    
    public EnumDomain(final Collection<T> values){
        this.set = new TreeSet<T>();
        this.set.addAll(values);
    }
    
    public EnumDomain(final T value){
        this(Arrays.asList(value));
    }

    public List<T> getDomainValues(){
        return Collections.unmodifiableList(new ArrayList<T>(this.set));
    }

    public EnumDomain<T> getDomain() {
        return this;
    }
    
    public int size() {
        return this.set.size();
    }

    public boolean isBound() {
        return (this.set.size() == 1);
    }

    public T getBoundValue() {
        if (!isBound())
            throw new IllegalStateException("cannot getBoundValue() for an Expression that is not isBound()");
        return this.set.iterator().next();
    }

    public boolean bind(final T value) throws InconsistentDomainException {
        return retain(new EnumDomain<T>(value));
    }

    public boolean retain(final EnumDomain<T> values) throws InconsistentDomainException {
        boolean result = this.set.retainAll(values.set);
        if (this.set.isEmpty())
            throw new InconsistentDomainException();
        return result;
    }

    public boolean remove(final EnumDomain<T> values) throws InconsistentDomainException {
        boolean result = this.set.removeAll(values.set);
        if (this.set.isEmpty())
            throw new InconsistentDomainException();
        return result;
    }

    public boolean remove(final T value) throws InconsistentDomainException {
        return remove(new EnumDomain<T>(value));
    }

    public boolean propagate() {
        return false;
    }
    
    @Override
    public String toString(){
        return "Enum[" + this.id + "]:" + this.set;
    }
    
}
